/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.rocketmq.store.logfile;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Iterator;
import org.apache.rocketmq.common.message.MessageExtBatch;
import org.apache.rocketmq.common.message.MessageExtBrokerInner;
import org.apache.rocketmq.store.AppendMessageCallback;
import org.apache.rocketmq.store.AppendMessageResult;
import org.apache.rocketmq.store.CompactionAppendMsgCallback;
import org.apache.rocketmq.store.PutMessageContext;
import org.apache.rocketmq.store.SelectMappedBufferResult;
import org.apache.rocketmq.store.TransientStorePool;
import org.apache.rocketmq.store.config.FlushDiskType;

/**
 * 在RocketMQ中，MappedFile是用于高效读写消息数据的核心组件之一。它利用了内存映射文件（Memory-Mapped File）技术来优化磁盘I/O操作。为了更好地管理这些文件中的数据，MappedFile引入了几个关键的位置指针：度位置（读位置）、写位置、刷新位置。下面详细解释这些概念及其重要性。
 *
 * 1. 写位置（Write Position）
 *      定义：指的是当前可以写入新数据的起始位置。
 *      作用：每当有新的消息需要存储时，就会从这个位置开始写入，之后更新该位置以反映已写入的数据长度。
 *      为什么需要：确保每次写入操作都是连续且不覆盖已有数据的关键。同时，它也是判断文件是否已满的一个重要依据。
 * 2. 读位置（度位置）
 *      定义：指的是当前可以从文件中安全读取数据的起始位置。
 *      作用：当消费者请求读取消息时，会从这个位置开始读取，直到达到某个预设的结束点或遇到未完成的消息块。
 *      为什么需要：保证消费者只能访问已经完全写入并提交的数据，避免读取到部分写入或者尚未确认的消息。
 * 3. 刷新位置（Flush Position）
 *      定义：表示已经被强制同步到磁盘的数据末尾位置。
 *      作用：尽管内存映射允许程序像访问内存一样快速访问文件内容，但为了防止系统崩溃导致的数据丢失，定期将内存中的修改同步到物理存储是非常必要的。
 *      为什么需要：
 *          持久化：确保即使发生意外断电等情况，最近写入的消息也不会丢失。
 *          一致性：维持内存视图与磁盘上的实际文件状态之间的一致性，这对于日志型消息队列尤为重要。
 * 为何需要刷新
 *      数据安全性：虽然内存映射提供了快速访问的能力，但它并不能保证数据即时写入磁盘。因此，通过设置刷新机制，可以在适当的时候（如达到一定时间间隔或累积了一定量的数据后）手动触发数据刷盘，从而提高数据的安全性和可靠性。
 *      性能考虑：过于频繁地刷新会影响性能；反之，如果刷新不够及时，则可能造成数据丢失风险增加。因此，找到一个合适的平衡点对于系统性能和稳定性都非常重要。
 *      综上所述，在RocketMQ的MappedFile设计中引入这三个位置是为了更精确地控制数据的读写过程，并通过适当的刷新策略来保障数据的完整性和系统的健壮性。这种设计使得RocketMQ能够在提供高性能的同时，也确保了数据的安全可靠。
 *
 *
 *
 */
public interface MappedFile {
    /**
     * Returns the file name of the {@code MappedFile}.
     * 1、返回 {@link MappedFile} 的文件名。
     * @return the file name
     */
    String getFileName();

    /**
     * Change the file name of the {@code MappedFile}.
     * <p> 2、修改 MapperdFile 的文件名。
     * @param fileName the new file name
     */
    boolean renameTo(String fileName);

    /**
     * Returns the file size of the {@code MappedFile}.
     * <p>3、返回 {@link MappedFile} 的文件大小。单位是 Byte。
     * @return the file size
     */
    int getFileSize();

    /**
     * Returns the {@code FileChannel} behind the {@code MappedFile}.
     * <p>4、返回 {@link MappedFile} 背后的 FileChannel。
     * @return the file channel
     */
    FileChannel getFileChannel();

    /**
     * Returns true if this {@code MappedFile} is full and no new messages can be added.
     *<p>5、判断 {@link MappedFile} 是否已满，不能再添加新的消息。
     * @return true if the file is full
     */
    boolean isFull();

    /**
     * Returns true if this {@code MappedFile} is available.
     * 6、判断 {@link MappedFile} 是否可用。
     * <p>
     * The mapped file will be not available if it's shutdown or destroyed.
     * <p> mapped file 关闭或者销毁后，它将不可用。
     *
     * @return true if the file is available
     */
    boolean isAvailable();

    /**
     * Appends a message object to the current {@code MappedFile} with a specific call back.
     * 7、向当前 {@link MappedFile} 追加一个消息对象，并执行特定的回调。
     * @param message a message to append
     * @param messageCallback the specific call back to execute the real append action
     * @param putMessageContext
     * @return the append result
     */
    AppendMessageResult appendMessage(MessageExtBrokerInner message, AppendMessageCallback messageCallback, PutMessageContext putMessageContext);

    /**
     * Appends a batch message object to the current {@code MappedFile} with a specific call back.
     * 8、添加 批量消息对象到当前 {@link MappedFile}，并执行特定的回调。
     * @param message a message to append
     * @param messageCallback the specific call back to execute the real append action
     * @param putMessageContext
     * @return the append result
     */
    AppendMessageResult appendMessages(MessageExtBatch message, AppendMessageCallback messageCallback, PutMessageContext putMessageContext);

    AppendMessageResult appendMessage(final ByteBuffer byteBufferMsg, final CompactionAppendMsgCallback cb);

    /**
     * Appends a raw message data represents by a byte array to the current {@code MappedFile}.
     *
     * @param data the byte array to append
     * @return true if success; false otherwise.
     */
    boolean appendMessage(byte[] data);

    /**
     * Appends a raw message data represents by a byte array to the current {@code MappedFile}.
     *
     * @param data the byte buffer to append
     * @return true if success; false otherwise.
     */
    boolean appendMessage(ByteBuffer data);

    /**
     * Appends a raw message data represents by a byte array to the current {@code MappedFile},
     * starting at the given offset in the array.
     *
     * @param data the byte array to append
     * @param offset the offset within the array of the first byte to be read
     * @param length the number of bytes to be read from the given array
     * @return true if success; false otherwise.
     */
    boolean appendMessage(byte[] data, int offset, int length);

    /**
     * Returns the global offset of the current {code MappedFile}, it's a long value of the file name.
     * <p>9、返回当前 {@link MappedFile} 的全局偏移量，它是文件名的长值（Long）。
     * @return the offset of this file
     */
    long getFileFromOffset();

    /**
     * Flushes the data in cache to disk immediately.
     * 10、立即将缓存中的数据刷新到磁盘。
     * @param flushLeastPages the least pages to flush
     * @return the flushed position after the method call
     */
    int flush(int flushLeastPages);

    /**
     * Flushes the data in the secondary cache to page cache or disk immediately.
     * 11、将二级缓存中的数据立即刷新到页缓存或磁盘。
     * @param commitLeastPages the least pages to commit
     * @return the committed position after the method call
     */
    int commit(int commitLeastPages);

    /**
     * Selects a slice of the mapped byte buffer's sub-region behind the mapped file,
     * starting at the given position.
     * 12、选择映射文件后面的字节缓冲区子区域的一个片段，从给定的位置开始。
     * @param pos the given position
     * @param size the size of the returned sub-region
     * @return a {@code SelectMappedBufferResult} instance contains the selected slice
     */
    SelectMappedBufferResult selectMappedBuffer(int pos, int size);

    /**
     * Selects a slice of the mapped byte buffer's sub-region behind the mapped file,
     * starting at the given position.
     *
     * @param pos the given position
     * @return a {@code SelectMappedBufferResult} instance contains the selected slice
     */
    SelectMappedBufferResult selectMappedBuffer(int pos);

    /**
     * Returns the mapped byte buffer behind the mapped file.
     * 返回 映射文件后面的字节缓冲区。
     * @return the mapped byte buffer
     */
    MappedByteBuffer getMappedByteBuffer();

    /**
     * Returns a slice of the mapped byte buffer behind the mapped file.
     * Returns 映射文件后面的字节缓冲区的一个片段。
     * @return the slice of the mapped byte buffer
     */
    ByteBuffer sliceByteBuffer();

    /**
     * Returns the store timestamp of the last message.
     * Returns 最后一条消息的存储时间戳。
     * @return the store timestamp
     */
    long getStoreTimestamp();

    /**
     * Returns the last modified timestamp of the file.
     * Returns 文件的最后修改时间戳。
     * @return the last modified timestamp
     */
    long getLastModifiedTimestamp();

    /**
     * Get data from a certain pos offset with size byte
     * 从 pos 偏移量处获取 size 个字节的数据
     * @param pos a certain pos offset to get data
     * @param size the size of data
     * @param byteBuffer the data
     * @return true if with data; false if no data;
     */
    boolean getData(int pos, int size, ByteBuffer byteBuffer);

    /**
     * Destroys the file and delete it from the file system.
     * 销毁 文件并从文件系统中删除它。
     * @param intervalForcibly If {@code true} then this method will destroy the file forcibly and ignore the reference
     * @return true if success; false otherwise.
     */
    boolean destroy(long intervalForcibly);

    /**
     * Shutdowns the file and mark it unavailable.
     * 关闭 文件并标记它不可用。
     * @param intervalForcibly If {@code true} then this method will shutdown the file forcibly and ignore the reference
     */
    void shutdown(long intervalForcibly);

    /**
     * Decreases the reference count by {@code 1} and clean up the mapped file if the reference count reaches at
     * {@code 0}.
     * 减少 引用计数 {@code 1} 并清理映射文件 如果引用计数达到 {@code 0}.
     *
     */
    void release();

    /**
     * Increases the reference count by {@code 1}.
     * 增加 引用计数 {@code 1}.
     * @return true if success; false otherwise.
     */
    boolean hold();

    /**
     * Returns true if the current file is first mapped file of some consume queue.
     * Returns 当前文件是否是某些消费队列的第一个映射文件。
     * @return true or false
     */
    boolean isFirstCreateInQueue();

    /**
     * Sets the flag whether the current file is first mapped file of some consume queue.
     * 设置 当前文件是否是某些消费队列的第一个映射文件的标志。
     * @param firstCreateInQueue true or false
     */
    void setFirstCreateInQueue(boolean firstCreateInQueue);

    /**
     * Returns the flushed position of this mapped file.
     * Returns 此映射文件的刷新位置。
     * @return the flushed posotion
     */
    int getFlushedPosition();

    /**
     * Sets the flushed position of this mapped file.
     * Sets 此映射文件的刷新位置。
     * @param flushedPosition the specific flushed position
     */
    void setFlushedPosition(int flushedPosition);

    /**
     * Returns the wrote position of this mapped file.
     * Returns 此映射文件的写入位置。
     * @return the wrote position
     */
    int getWrotePosition();

    /**
     * Sets the wrote position of this mapped file.
     * Sets 此映射文件的写入位置。
     * @param wrotePosition the specific wrote position
     */
    void setWrotePosition(int wrotePosition);

    /**
     * Returns the current max readable position of this mapped file.
     * Returns 此映射文件的当前最大可读位置。
     * @return the max readable position
     */
    int getReadPosition();

    /**
     * Sets the committed position of this mapped file.
     * Sets 此映射文件的提交位置。
     * @param committedPosition the specific committed position
     */
    void setCommittedPosition(int committedPosition);

    /**
     * Lock the mapped bytebuffer
     * 锁定 映射的 bytebuffer
     */
    void mlock();

    /**
     * Unlock the mapped bytebuffer
     * 解锁 映射的 bytebuffer
     */
    void munlock();

    /**
     * Warm up the mapped bytebuffer
     * 预热 映射的 bytebuffer
     * @param type
     * @param pages
     */
    void warmMappedFile(FlushDiskType type, int pages);

    /**
     * Swap map
     * 交换 映射
     */
    boolean swapMap();

    /**
     * Clean pageTable
     * 清理 pageTable
     */
    void cleanSwapedMap(boolean force);

    /**
     * Get recent swap map time
     * 获取当前 交换映射时间
     */
    long getRecentSwapMapTime();

    /**
     * Get recent MappedByteBuffer access count since last swap
     * 获取 最后一次交换映射以来的 MappedByteBuffer 访问次数
     */
    long getMappedByteBufferAccessCountSinceLastSwap();

    /**
     * Get the underlying file
     * 获取 底层文件
     * @return
     */
    File getFile();

    /**
     * rename file to add ".delete" suffix
     * 修改 文件名称 添加 ".delete" 后缀
     */
    void renameToDelete();

    /**
     * move the file to the parent directory
     * 移动 文件到 父目录
     * @throws IOException
     */
    void moveToParent() throws IOException;

    /**
     * Get the last flush time
     * 获取 最后刷新时间
     * @return
     */
    long getLastFlushTime();

    /**
     * Init mapped file
     * 初始化 映射文件
     * @param fileName file name
     * @param fileSize file size
     * @param transientStorePool transient store pool
     * @throws IOException
     */
    void init(String fileName, int fileSize, TransientStorePool transientStorePool) throws IOException;

    Iterator<SelectMappedBufferResult> iterator(int pos);

    /**
     * Check mapped file is loaded to memory with given position and size
     * 检查 映射文件 是否 已加载到内存 给定的位置和大小
     * @param position start offset of data
     * @param size data size
     * @return data is resided in memory or not
     */
    boolean isLoaded(long position, int size);
}
